﻿using MediatR;
using Microsoft.Extensions.Logging;
using Sgr.Application.Commands;
using Sgr.Domain.Entities;
using Sgr.Identity.Services;
using Sgr.Security.VerifyCode;
using Sgr.UPMS.Domain.Organizations;
using Sgr.UPMS.Domain.Users;

namespace Sgr.UPMS.Application.Commands.Users
{
    public class RegisterUserCommandHandle : IRequestHandler<RegisterUserCommand, CommandResult<bool>>
    {
        private readonly IUserManage _userManage;
        private readonly IOrganizationManage _organizationManage;
        private readonly IUserRepository _userRepository;
        private readonly IPasswordHashService _passwordHashService;
        private readonly IVerifyCodeService _verifyCodeService;
        private readonly ILogger<RegisterUserCommandHandle> _logger;

        #region 常量定义

        private const string SUCCESS_MESSAGE = "用户注册成功";
        private const string INVALID_INVITATION_CODE_MESSAGE = "组织邀请码无效或已过期";

        #endregion 常量定义

        /// <summary>
        /// 构造函数
        /// </summary>
        public RegisterUserCommandHandle(
            IUserManage userManage,
            IOrganizationManage organizationManage,
            IUserRepository userRepository,
            IPasswordHashService passwordHashService,
            IVerifyCodeService verifyCodeService,
            ILogger<RegisterUserCommandHandle> logger)
        {
            _userManage = userManage ?? throw new ArgumentNullException(nameof(userManage));
            _organizationManage = organizationManage ?? throw new ArgumentNullException(nameof(organizationManage));
            _userRepository = userRepository ?? throw new ArgumentNullException(nameof(userRepository));
            _passwordHashService = passwordHashService ?? throw new ArgumentNullException(nameof(passwordHashService));
            _verifyCodeService = verifyCodeService ?? throw new ArgumentNullException(nameof(verifyCodeService));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        public async Task<CommandResult<bool>> Handle(RegisterUserCommand request, CancellationToken cancellationToken)
        {
            // 1. 验证码校验
            bool isValidCode = await _verifyCodeService.VerifyAsync(
                request.AuthenticationType == UserAuthenticationType.PhoneNumber ? ReceiverType.Phone : ReceiverType.Email,
                request.Account,
                request.VerificationCode,
                request.VerificationPurpose,
                true,
                cancellationToken);

            if (!isValidCode)
            {
                return CommandResult.Invalid<bool>(Constant.INVALID_VERIFYCODE_MESSAGE);
            }

            // 2. 如果组织邀请码存在，则必须验证
            if (string.IsNullOrEmpty(request.OrgInvitationCode))
                return CommandResult.Invalid<bool>(INVALID_INVITATION_CODE_MESSAGE);

            var invitationResult = await _organizationManage.ValidateInvitationAsync(
                    request.OrgInvitationCode!,
                    cancellationToken);

            if (!invitationResult.IsValid)
                return CommandResult.Invalid<bool>(INVALID_INVITATION_CODE_MESSAGE);

            long orgId = invitationResult.Invitation!.OrganizationId;

            // 3. 账号唯一性检查
            var uniqueCheckResult = await ValidateAccountUniqueness(request, cancellationToken);
            if (!uniqueCheckResult.IsComply)
            {
                return CommandResult.Invalid<bool>(uniqueCheckResult.Message);
            }

            // 4. 创建用户
            var user = await CreateUser(request, orgId, cancellationToken);

            user.DifferenceUpdateRoles(new long[] { Constant.NORMAL_USER_ROLE_ID }, true);

            // 5. 绑定
            user.SetUserInfo(request.UserName, Gender.Unknown, null, null);
            BindUserAccount(user, request.Account, request.AuthenticationType);

            // 6. 保存用户
            await _userRepository.InsertAsync(user, cancellationToken);

            return CommandResult.Success(true, SUCCESS_MESSAGE);
        }

        #region 私有辅助方法

        /// <summary>
        /// 验证账号唯一性
        /// </summary>
        private async Task<DomainRuleCheckResult> ValidateAccountUniqueness(
            RegisterUserCommand request,
            CancellationToken cancellationToken)
        {
            return request.AuthenticationType switch
            {
                UserAuthenticationType.PhoneNumber =>
                    await _userManage.ValidatePhoneNumberUniquenessAsync(request.Account, null, cancellationToken),
                UserAuthenticationType.Email =>
                    await _userManage.ValidateEmailUniquenessAsync(request.Account, null, cancellationToken),
                _ => DomainRuleCheckResult.Fail("不支持的验证类型")
            };
        }

        /// <summary>
        /// 创建用户
        /// </summary>
        private async Task<User> CreateUser(RegisterUserCommand request, long orgId, CancellationToken cancellationToken)
        {
            string userName;
            if (!string.IsNullOrWhiteSpace(request.UserName))
                userName = request.UserName;
            else
                userName = await Organizations.RegisterOrgCommandHadle.GenerateUniqueLoginNameAsync(_userManage, cancellationToken);

            return await _userManage.CreateNewAsync(
                userName,
                _passwordHashService,
                request.LoginPassword ?? Constant.DEFAULT_PASS_WORD,
                false, // 非管理员用户
                orgId,    // 组织ID将通过邀请码关联
                cancellationToken);
        }

        /// <summary>
        /// 绑定用户账号
        /// </summary>
        private static void BindUserAccount(User user, string account, UserAuthenticationType authenticationType)
        {
            switch (authenticationType)
            {
                case UserAuthenticationType.PhoneNumber:
                    user.BindPhoneNumber(account, true);
                    break;

                case UserAuthenticationType.Email:
                    user.BindUserEmail(account, true);
                    break;

                default:
                    throw new ArgumentException("不支持的验证类型", nameof(authenticationType));
            }
        }

        #endregion 私有辅助方法
    }
}